package singleton.dcl;

public class Singleton {

    private volatile static Singleton singleton;

    private Singleton() {
    }

    public static Singleton getSingleton() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                /**
                 * @Question 为什么需要第二次再次检查singleton是否为null？
                 * 假如singleton还为null，且有两个线程A，B分别想要获取singleton对象；现在A线程获得了锁；
                 * 在A线程还没有完成对singleton引用的赋值前，此时CPU切换到了线程B，所以singleton还为空，
                 * 于是线程B成功越过第一个singleton==null判断，但是线程B最终还是在执行临界区前阻塞，因为在
                 * A没有释放锁的情况下，B是无法得到锁从而进入临界区。当再次轮到A执行时，假设A成功的创建了Sing-
                 * leton对象，在这种情况下B线程就没有必要再创建Singleton对象了，但是B之后任然会获得锁，从而
                 * 执行临界区中的代码，从而有必要再次进行检查singleton是否为null，以免B重复对Singleton对象
                 * 进行创建。
                 */
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}
